package ast;

import java.util.ArrayList;

import symbol.astPreprocessContext;

public class ComplexDataSignature extends DataSignature {
	// 操作包括：函数传参、类访问属性、类调用方法、数组寻址、数组声明
	public enum operationType {
		CALL_FUNC, CLASS_ATTR, CLASS_METHOD, ARRAY_LOC, ARRAY_DECL, ARRAY_PARAM
	}
	// 被“操作”的数据类型(新增字段，用于类型推断)
	public String dataType;
	public DataSignature dataOperated;
	// 操作包括：函数传参、类访问属性、类调用方法、数组寻址、数组声明
	public operationType opType;
	// （1）函数传参：operation中包含多个实参的DataSignature
	// （2）类访问属性：operation中包含属性的Signature
	// （3）类调用方法：operation中包含类方法的Signature(要个名字就行，参数不用管，放在下一层就好)
	// （4）数组寻址：operation中包含数组的维度访问信息（从低维到高维，如果是全取则传入常量-1）
	// (5) 数组声明
	public ArrayList<AstItem> operation = new ArrayList<AstItem>();
	
	public String ptrTransform;
	public String funckey;
	
	public Boolean isMethod  = false;
	public String methodName;
	
	public Boolean isFuncAttr = false;
	
//	public void updateFunckey(ArrayList<String> paramsType) {
//		String result = "_";
//		if (astPreprocessContext.getClassList().contains(name)) {
//			// 类的构造器
//			result += name + "_constructor_";
//			for (String type: paramsType) {
//				result += type + "_";
//			}
//			funckey = result;
//		} else {
//			result += name + "_";
//			for (String type: paramsType) {
//				result += type + "_";
//			}
//			funckey = result;
//		}
//	}

	public String getTypeC(String t) {
		String[] typeInfo = t.split("_");
		assert typeInfo.length > 0;
		String type_c = typeInfo[0];
		if (typeInfo[0].equals("bool")) type_c = "int";
		else if (typeInfo[0].equals("longlong")) type_c = "long long";
		else if (typeInfo[0].equals("string")) type_c = "char[]";
		else if (typeInfo[0].contains("func")) type_c = "void*";
		else if (astPreprocessContext.getClassList().contains(typeInfo[0])) type_c = "struct " + typeInfo[0] + "*";
		return type_c;
	}
	
	public void updatePtrTransform(ArrayList<String> paramsType) {
		// 类的方法也需要更新funckey（打一下补丁，因为类的方法是complex，不能更新funckey）
		if (isMethod == true && isFuncAttr == false) {
			String result = "_";
			result += methodName + "_";
			for (String type: paramsType) {
				result += type + "_";
			}
			result = result.replace("<", "_");
			result = result.replace(">", "");
			funckey = result;
			((PrimaryDataSignature) operation.get(0)).isMethod = true;
			((PrimaryDataSignature) operation.get(0)).methodName = methodName;
			((PrimaryDataSignature) operation.get(0)).updateFunckey(paramsType);
//			System.out.println(funckey + "***");
			return;
		}
		String result = "(" + getTypeC(dataType.substring(5, dataType.length() - 1)) + "(*) (";
		for (int i = 0;i < paramsType.size();i++) {
			result += getTypeC(paramsType.get(i));
			if (i != paramsType.size() - 1) {
				result += ", ";
			}
		}
		result += "))";
		ptrTransform = result;
//		if (isFuncAttr == true) System.out.println(ptrTransform);
	}
	
	public String toString() {
//		System.out.println(this.opType + "999");
		String result = "";
		switch (this.opType) {
			case CALL_FUNC:
				// 函数传参
				if (dataOperated instanceof ComplexDataSignature && ((ComplexDataSignature) dataOperated).isMethod == true) {
					// 如果上一层是method
					result = dataOperated.toString();
					for (int i = 0;i < this.operation.size();i++) {
						result += ", ";
						result += ((Expression) this.operation.get(i)).toString();
					}
					result += ")";
				} else {
					result = dataOperated.toString() + "(";
					for (int i = 0;i < this.operation.size();i++) {
						result += ((Expression) this.operation.get(i)).toString();
						if (i < this.operation.size() - 1) result += ", ";
					}
					result += ")";
				}
//				if (isFuncAttr != null) System.out.println("...");
//				if (dataOperated instanceof ComplexDataSignature && ((ComplexDataSignature) dataOperated).isFuncAttr == true) {
//					if (((ComplexDataSignature) dataOperated).ptrTransform != null) {
//						return "(" + ((ComplexDataSignature) dataOperated).ptrTransform + " " + result + ")";
//					}
//				}
				if (ptrTransform != null) {
					return "(" + ptrTransform + " " + result + ")";
				}
				return result;
			case CLASS_ATTR:
				// 类访问属性
				result = dataOperated.toString() + "->" + ((PrimaryDataSignature) this.operation.get(0)).toString();
				if (ptrTransform != null) {
					return "(" + ptrTransform + " " + result + ")";
				}
				return result;
			case CLASS_METHOD:
				// 类调用方法
				if (isMethod == true) {
					result = ((PrimaryDataSignature) this.operation.get(0)).toString() + "(" + dataOperated.toString();
				} else {
					result = dataOperated.toString() + "->" + ((PrimaryDataSignature) this.operation.get(0)).toString();
				}
				if (ptrTransform != null && isFuncAttr == true) {
					return "(" + ptrTransform + " " + result + ")";
				}
				return result;
			case ARRAY_LOC:
				// 数组寻址
				result = this.dataOperated.toString();
				for (int i = 0;i < this.operation.size();i++) {
					result += "[" + ((Expression) this.operation.get(i)).toString() + "]";
				}
//				System.out.println(result);
				if (ptrTransform != null) {
					return "(" + ptrTransform + " " + result + ")";
				}
				return result;
			case ARRAY_DECL:
				// 数组声明
				result = ((PrimaryDataSignature) this.dataOperated).getDeclString() + " " + this.dataOperated.toString();
				for (int i = 0;i < this.operation.size();i++) {
					result += "[" + ((Expression) this.operation.get(i)).toString() + "]";
				}
//				System.out.println(result);
				if (ptrTransform != null) {
					return "(" + ptrTransform + " " + result + ")";
				}
				return result;
			case ARRAY_PARAM:
				// 数组作为形参
				result = ((PrimaryDataSignature) this.dataOperated).getDeclString() + " " + this.dataOperated.toString();
				for (int i = 0;i < this.operation.size();i++) {
					String dim = (this.operation.get(i)).toString();
					if (!dim.equals("-1")) result += "[" + dim + "]";
					else result += "[]";
				}
				if (ptrTransform != null) {
					return "(" + ptrTransform + " " + result + ")";
				}
				return result;
		}
		return "";
	}
	
	public String getDataType(AstItem x) {
		assert ((x instanceof PrimaryDataSignature) || (x instanceof ComplexDataSignature) || (x instanceof Expression));
		if (x instanceof PrimaryDataSignature) {
			return ((PrimaryDataSignature) x).dataType;
		} else if (x instanceof ComplexDataSignature) {
			return ((ComplexDataSignature) x).dataType;
		} else {
			// 表达式
			return ((Expression) x).dataType;
		}
	}
	
	public void preprocess(AstItem father) {
		if (dataOperated instanceof PrimaryDataSignature && 
				astPreprocessContext.getNowClass() != null && 
				((PrimaryDataSignature) dataOperated).name.equals("this")) {
			// class定义中的this变量
			astPreprocessContext.getContext();
			((PrimaryDataSignature) dataOperated).dataType = astPreprocessContext.getNowClass();
		} else {
			dataOperated.preprocess(this);
		}
		for (AstItem x : operation) {
			x.preprocess(this);
		}
		// 下面做类型推断
		if (opType == operationType.CLASS_ATTR) {
			assert operation.size() == 1;
			assert operation.get(0) instanceof PrimaryDataSignature;
			// 查看dataOperated是什么class，并查表获得属性的类型
			String varName = getDataType(dataOperated) + "#" + ((PrimaryDataSignature) operation.get(0)).name;
			astPreprocessContext.getContext();
//			System.out.println(astPreprocessContext.toDebugString());
			this.dataType = astPreprocessContext.getGlobalSymbolTables().getSymbolInfo(varName).typeToString();
		} else if (opType == operationType.CLASS_METHOD) {
			// 查看获得method的类型/func属性
			assert operation.size() == 1;
			assert operation.get(0) instanceof PrimaryDataSignature;
			String varName = getDataType(dataOperated) + "_" + ((PrimaryDataSignature) operation.get(0)).name;
//			System.out.println(varName);
			astPreprocessContext.getContext();
			this.dataType = astPreprocessContext.getFuncType(varName);
			isMethod = true;
			methodName = varName;
			if (this.dataType == null) {
				// func属性
				isMethod = false;
				isFuncAttr = true;
				varName = getDataType(dataOperated) + "#" + ((PrimaryDataSignature) operation.get(0)).name;
				astPreprocessContext.getContext();
				this.dataType = astPreprocessContext.getGlobalSymbolTables().getSymbolInfo(varName).typeToString();
			}
		} else if (opType == operationType.CALL_FUNC) {
			// 如果是类的构造器，则class->func<class>
			if (dataOperated instanceof PrimaryDataSignature && 
					astPreprocessContext.getClassList().contains(((PrimaryDataSignature)dataOperated).name)) {
				((PrimaryDataSignature)dataOperated).dataType = "func<" + ((PrimaryDataSignature)dataOperated).name + ">";
			}
			// 查看dataOperated是什么类型的函数，本层的类型为函数返回值类型
			String funcType = getDataType(dataOperated);
			this.dataType = funcType.substring(5, funcType.length() - 1);
			// 如果是函数变量，则记录在函数变量记录表中
			astPreprocessContext.getContext();
			if (dataOperated instanceof PrimaryDataSignature) {
				String name = ((PrimaryDataSignature) dataOperated).name;
				if (astPreprocessContext.getNowSymbolTables().containsSymbol(name)) {
					ArrayList<String> paramsType = new ArrayList<>();
					for (AstItem x : operation) {
						paramsType.add(getDataType(x));
					}
//					((PrimaryDataSignature) dataOperated).updateFunckey(paramsType);
					((PrimaryDataSignature) dataOperated).updatePtrTransform(paramsType);
					astPreprocessContext.addFuncvarInfo(name, paramsType, this.dataType);
				} else {
					ArrayList<String> paramsType = new ArrayList<>();
					for (AstItem x : operation) {
						paramsType.add(getDataType(x));
					}

					// 普通函数:更新Funckey和PtrTransform
					// 类的构造器在这里，没有更新funckey
					((PrimaryDataSignature) dataOperated).updateFunckey(paramsType);
//					((PrimaryDataSignature) dataOperated).updatePtrTransform(paramsType);
				}
			}
			// 更新PtrTransform
			if (dataOperated instanceof ComplexDataSignature) {
				ArrayList<String> paramsType = new ArrayList<>();
				for (AstItem x : operation) {
					paramsType.add(getDataType(x));
				}
				// 类的方法在这里，没有更新funckey,不应该更新ptrTransform
//				((ComplexDataSignature) dataOperated).updateFunckey(paramsType);
				((ComplexDataSignature) dataOperated).updatePtrTransform(paramsType);
			}
		} else if (opType == operationType.ARRAY_LOC) {
			// 寻址，查看dataOperated的类型和维度，根据本层操作减少维数
			String arrayType = getDataType(dataOperated);
			// 如果是string，则返回char
			if (arrayType == "string") {
				this.dataType = "char";
				return;
			}
			// 不是string
			String[] arrayTypeInfoList = arrayType.split("_");
			assert arrayTypeInfoList.length == 2;
			int dimCount = Integer.parseInt(arrayTypeInfoList[1]) - operation.size();
			assert dimCount >= 0;
			if (dimCount > 0) this.dataType = arrayTypeInfoList[0] + "_" + String.valueOf(dimCount);
			else this.dataType = arrayTypeInfoList[0];
		} else if (opType == operationType.ARRAY_DECL) {
			// 数组声明，类型不变，直接赋值
			this.dataType = getDataType(dataOperated);
		} else if (opType == operationType.ARRAY_PARAM) {
			// 数组参数，类型不变，直接赋值
			this.dataType = getDataType(dataOperated);
		}
		assert this.dataType != null;
	}

	@Override
	public String toJsonString() {
		String json = "{";
		json += "\"Type\": \"DataSignature-" + type.toString() + "\",";
		json += "\"DataOperated\": ";
		json += dataOperated.toJsonString() + ",";
		json += "\"OpType\": \"";
		json += opType.toString() + "\",";
		json += "\"Operation\": [";
		for (AstItem astItem: operation) {
			json += astItem.toJsonString() + ",";
		}
		json += "]}";
		return json;
	}
}
